package com.molichuxing.gateway.utils;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.molichuxing.framework.contants.RedisKeyConst;
import com.molichuxing.framework.utils.Md5Util;
import com.molichuxing.framework.utils.RedisUtil;
import com.molichuxing.framework.utils.StringUtil;
import com.molichuxing.gateway.bff.permission.entity.response.ResourceVo;
import com.molichuxing.services.business.service.SmsBizService;
import com.molichuxing.services.infrastructure.dto.response.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.GroupSystemTypeEnum;
import com.molichuxing.services.property.StatusEnum;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 数据字典工具类
 * 
 * @author zoumingyu
 * @date 2019年8月19日
 *
 */
@Component
public class RedisPermissionUtil implements ApplicationListener<ContextRefreshedEvent> {
	private static final Logger logger = LoggerFactory.getLogger(RedisPermissionUtil.class);

	@Resource
	private GroupService  groupService;

	@Resource
	private GroupResourceService groupResourceService;

	@Resource
	private ResourceService resourceService;

	@Resource
	private GroupDesenseService groupDesenseService;

	@Resource
	private DesenseService desenseService;

	@Resource
	private SensitiveWordService sensitiveWordService;

	@Resource
	private RedisUtil redisUtil;

	// 环境
	@Value("${profiles.active}")
	private String active;

	/**
	 * 启动后加载所有角色对应权限和脱敏字段到redis
	 * @param event
	 */
	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		setResourceToRedisByTotalGroup();
		setDesenseToRedisByTotalGroup();
		setSensitiveWordToRedis();
	}

	/**************************************************权限******************************************************/
	/**
	 * 获取所有可用得角色，并获取其绑定得权限放入redis、
	 */
	public void setResourceToRedisByTotalGroup() {
		Map<String, Object> getGroupParam = new HashMap<>();
		getGroupParam.put("groupSystemType", GroupSystemTypeEnum.MOLI.getValue());
		getGroupParam.put("status", StatusEnum.OPEN.getValue());
		List<GroupDto> groupList = groupService.getGroupListByParm(getGroupParam);
		if (CollectionUtils.isNotEmpty(groupList)) {
			groupList.forEach(groupDto -> {
				resourceToRedis(groupDto.getId(), groupDto.getGroupSystemType());
			});
		}
	}

	/**
	 * 将角色绑定的权限放入redis
	 * @param groupId
	 */
	public synchronized void resourceToRedis(int groupId, GroupSystemTypeEnum systemType) {
		String dbType = null;
		if (systemType.getValue() == GroupSystemTypeEnum.MOLI.getValue()) {
			dbType = RedisKeyConst.OP_GROUP_PERMISSION;
		} else {
			dbType = RedisKeyConst.DEALER_GROUP_PERMISSION;
		}
		if (groupId > 0) {
			String key =  dbType + Md5Util.md5Hex(active) +"."+  Md5Util.md5Hex(String.valueOf(groupId));
			redisUtil.del(key);

			final List<Integer> resourceIds = new ArrayList<>();

			//查询角色与权限的关联表
			Map<String, Object> getGroupResourceParam = new HashMap<>();
			getGroupResourceParam.put("groupId", groupId);
			List<GroupResourceDto> groupResourceList = groupResourceService.getGroupResourceListByParm(getGroupResourceParam);
			if (CollectionUtils.isNotEmpty(groupResourceList)) {
				groupResourceList.forEach(groupResource -> {
					resourceIds.add(groupResource.getResourceId()); //将角色拥有的权限id放入集合
				});
			}

			//查询角色所拥有的权限
			if (CollectionUtils.isNotEmpty(resourceIds)) {
				Map<String, Object> getResourceMap = new HashMap<>();
				getResourceMap.put("ids", resourceIds);
				List<ResourceDto> rsourceList = resourceService.getResourceListByParam(getResourceMap);
				if (CollectionUtils.isNotEmpty(rsourceList)) {
					final Map<String, String> collect = new HashMap<String, String>();
					rsourceList.forEach(resourceDto -> {
						if (!StringUtil.isEmpty(resourceDto.getUri())) {
							String[] uriArr = resourceDto.getUri().split(",");
							if (uriArr.length > 1) {
								for (String uri : uriArr) {
									if (collect.get(uri) == null) {
										collect.put(uri, Boolean.TRUE.toString());
									}
								}
							} else {
								if (collect.get(resourceDto.getUri()) == null) {
									collect.put(resourceDto.getUri(), Boolean.TRUE.toString());
								}
							}
						}

					});
					redisUtil.hmset(key, collect);
				}
			}
		}
	}

	/**
	 * 删除指定角色得权限数据
	 * @param group
	 */
	public synchronized void deleteResourceByGroupId(GroupDto group) {
		if (group != null && group.getId() > 0 && group.getGroupSystemType() != null) {

			String key = "";
			if (group.getGroupSystemType().getValue() == GroupSystemTypeEnum.MOLI.getValue()) {
				//删除角色在redis中的权限
				key =  RedisKeyConst.OP_GROUP_PERMISSION + Md5Util.md5Hex(active) +"."+  Md5Util.md5Hex(group.getId()+"");
			} else {
				key =  RedisKeyConst.DEALER_GROUP_PERMISSION + Md5Util.md5Hex(active) +"."+  Md5Util.md5Hex(group.getId()+"");
			}

			if (!StringUtil.isEmpty(key))
				redisUtil.del(key);
		}
	}

	/**************************************************权限End******************************************************/


	/**************************************************脱敏******************************************************/

	/**
	 * 获取所有可用得脱敏字段，并获取其绑定得脱敏字段放入redis、
	 */
	public void setDesenseToRedisByTotalGroup() {
		Map<String, Object> getGroupParam = new HashMap<>();
		getGroupParam.put("groupSystemType", GroupSystemTypeEnum.MOLI.getValue());
		getGroupParam.put("status", StatusEnum.OPEN.getValue());
		List<GroupDto> groupList = groupService.getGroupListByParm(getGroupParam);
		if (CollectionUtils.isNotEmpty(groupList)) {
			groupList.forEach(groupDto -> {
				desenseToRedis(groupDto.getId());
			});
		}

	}

	/**
	 * 将角色绑定的脱敏字段放入redis
	 * @param groupId
	 */
	public synchronized void desenseToRedis(int groupId) {
		if (groupId > 0) {
			String key =  RedisKeyConst.OP_GROUP_DESENSE + Md5Util.md5Hex(active) +"."+  Md5Util.md5Hex(String.valueOf(groupId));
			redisUtil.del(key);

			Map<String, Object> getGroupDesenseParam = new HashMap<>();
			getGroupDesenseParam.put("groupId", groupId);
			List<GroupDesenseDto> groupDesenseList = groupDesenseService.getGroupDesenseListByParam(getGroupDesenseParam);

			final  List<Integer> desenseIds = new ArrayList<>();
			if (CollectionUtils.isNotEmpty(groupDesenseList)) {
				groupDesenseList.forEach(groupDesenseDto -> {
					desenseIds.add(groupDesenseDto.getDesenseId());
				});
			}

			if (CollectionUtils.isNotEmpty(desenseIds)) {
				Map<String, Object> getDesenseParam = new HashMap<>();
				getDesenseParam.put("ids", desenseIds);

				final Map<String, String> valueMap = new HashMap<>();
				List<DesenseDto> desenseList = desenseService.getDesenseListByParam(getDesenseParam);
				desenseList.forEach(desenseDto -> {
					if (!StringUtil.isEmpty(desenseDto.getFieldName()) && !StringUtil.isEmpty(desenseDto.getVoName())) {
						String[] voNameArr = desenseDto.getVoName().split(",");
						if (voNameArr.length > 1) {
							for (String voName : voNameArr) {
								if (valueMap.get(voName +"-"+ desenseDto.getFieldName()) == null) {
									valueMap.put(voName +"-"+ desenseDto.getFieldName(), JSON.toJSONString(desenseDto));
								}
							}
						} else {
							if (valueMap.get(desenseDto.getVoName() +"-"+ desenseDto.getFieldName()) == null) {
								valueMap.put(desenseDto.getVoName() +"-"+ desenseDto.getFieldName(), JSON.toJSONString(desenseDto));
							}
						}
					}
				});
				redisUtil.hmset(key, valueMap);

			}
		}
	}

	public ResourceVo getDesenseByGroupIdAndField(int groupId, String field) {
		if (groupId > 0) {
			String key =  RedisKeyConst.OP_GROUP_DESENSE + Md5Util.md5Hex(active) +"."+  Md5Util.md5Hex(String.valueOf(groupId));
			return JSONObject.parseObject(redisUtil.hget(key, field), ResourceVo.class);
		}
		return null;
	}

	public Map<String, String> getDesenseByGroupId(int groupId) {
		if (groupId > 0) {
			String key =  RedisKeyConst.OP_GROUP_DESENSE + Md5Util.md5Hex(active) +"."+  Md5Util.md5Hex(String.valueOf(groupId));
			return redisUtil.hgetAll(key);
		}
		return null;
	}
	/**************************************************脱敏End******************************************************/

	/**************************************************敏感词******************************************************/

	/**
	 * 敏感词放入redis
	 */
	public void setSensitiveWordToRedis() {
		String key = RedisKeyConst.OP_SENSITIVE_WORD + "permission_sensitive_word";

		redisUtil.del(key);

		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("status", StatusEnum.OPEN.getValue());
		List<SensitiveWordDto> wordsList = sensitiveWordService.getSensitiveWordByParam(paramMap);
		final Map<String, String> valueMap = new HashMap<>();
		if (CollectionUtils.isNotEmpty(wordsList)) {
			wordsList.forEach(words -> {
				valueMap.put(Base64.encode(words.getWords()), JSON.toJSONString(words));
			});
		}

		if (valueMap != null && valueMap.size() > 0) {
			redisUtil.hmset(key, valueMap);
		}
	}

	public Map<String, String> getSensitiveWords() {
		String key = RedisKeyConst.OP_SENSITIVE_WORD + "permission_sensitive_word";
		return redisUtil.hgetAll(key);
	}
	/**************************************************敏感词END******************************************************/

}
